<template>
	<div :class="mobile.toLowerCase()" class="vhd-container">
		<input v-model="value" :placeholder="placeholder" type="text" class="vhd-input" aria-label="vue-hotel-datepicker-input" @click="active = !active" />
		<div v-if="active" class="vhd-picker">
			<div class="vhd-calendar">
				<div class="vhd-calendar-header">
					<a class="close" @click="close"><IconClose /></a>
					<span class="info" v-if="is_add">
						<span v-if="selectStartDate" class="from-text">{{ fromText }}</span>
						<span v-if="selectStartDate" class="from-date">{{ displayDateText(selectStartDate) }}</span>
						<span v-if="selectEndDate" class="to-text">{{ toText }}</span>
						<span v-if="selectEndDate" class="from-date">{{ displayDateText(selectEndDate) }}</span>
					</span>
				</div>
				<div class="vhd-calendar-left">
					<div class="calendar-month">
						<div class="calendar-month-title">{{ startMonthDate.getFullYear() }} - {{ monthList[startMonthDate.getMonth()] }}</div>
					</div>
					<div class="calendar-week">
						<div v-for="(wItem, index) in weekList" :key="index" class="calendar-week-item">{{ wItem }}</div>
					</div>
					<div class="calendar-date">
						<div v-for="(week, wIndex) in startMonthAry" :key="wIndex" class="week">
							<div v-for="(startDay, dIndex) in week" :key="dIndex" :class="dayStatus(startDay)" class="day" @click="dayOnClick(startDay)">
								<span v-if="startDay">{{ startDay.getDate() }}</span>
							</div>
						</div>
					</div>
				</div>
				<div class="vhd-calendar-right">
					<div class="calendar-month">
						<a class="next-arrow" @click="updateCalendar(2)"><IconArrowForward class="arrow" /></a>
						<div class="calendar-month-title">{{ monthList[endMonthDate.getMonth()] }} {{ endMonthDate.getFullYear() }}</div>
					</div>
					<div class="calendar-week">
						<div v-for="(wItem, index) in weekList" :key="index" class="calendar-week-item">{{ wItem }}</div>
					</div>
					<div class="calendar-date">
						<div v-for="(week, wIndex) in endMonthAry" :key="wIndex" class="week">
							<div v-for="(endDay, dIndex) in week" :key="dIndex" :class="dayStatus(endDay)" class="day" @click="dayOnClick(endDay)">
								<span v-if="endDay">{{ endDay.getDate() }}</span>
							</div>
						</div>
					</div>
				</div>
				<!-- //切换月份 -->
				<div class="mouth">
					<a :class="disabledPreviousArrow(startMonthDate)" class="previous-arrow offset-1" @click="updateCalendar(-1)"><IconArrowBack class="arrow" /><span>{{monthList[startMonthDate.getMonth()]-1}}月</span></a>
					<a class="previous-arrow offset-1" @click="updateCalendar(1)"><span>{{monthList[startMonthDate.getMonth()+1]}}月</span><IconArrowForward class="arrow" /></a>
				</div>
				<div class="vhd-calendar-footer">
					<div v-if="is_add" class="reset" @click="reset">{{ resetText }}</div>
					<div class="confirm" @click="confirm">{{ confirmText }}</div>
				</div>
			</div>
		</div>
	</div>
</template>
<script>
import IconClose from '@/components/icon/IconClose';
import IconArrowBack from '@/components/icon/IconArrowBack';
import IconArrowForward from '@/components/icon/IconArrowForward';
export default {
	name: 'VueHotelDatepicker',
	components: {
		IconClose,
		IconArrowBack,
		IconArrowForward
	},
	directives: {},
	props: {
		placeholder: {
			type: String,
			default: 'Select a date range'
		},
		seperator: {
			type: String,
			default: '~'
		},
		format: {
			type: String,
			default: 'YYYY/MM/DD'
		},
		startDate: {
			type: [String, Date],
			default: undefined
		},
		endDate: {
			type: [String, Date],
			default: undefined
		},
		minDate: {
			type: [String, Date],
			default: () => new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), 0, 0, 0)
		},
		maxDate: {
			type: [String, Date, Boolean],
			default: false
		},
		minNight: {
			type: Number,
			default: undefined
		},
		maxNight: {
			type: Number,
			default: undefined
		},
		selectForward: {
			type: Boolean,
			default: true
		},
		disabledDates: {
			type: Array,
			default: () => []
		},
		weekList: {
			type: Array,
			default: () => ['日', '一', '二', '三', '四', '五', '六']
		},
		monthList: {
			type: Array,
			default: () => ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
		},
		fromText: {
			type: String,
			default: 'From'
		},
		toText: {
			type: String,
			default: 'To'
		},
		resetText: {
			type: String,
			default: 'Reset'
		},
		confirmText: {
			type: String,
			default: '确认'
		},
		mobile: {
			type: String,
			default: 'mobile' // mobile or desktop
		}
	},
	data() {
		return {
			value: '',
			active: false,
			startMonthDate: undefined,
			endMonthDate: undefined,
			selectStartDate: undefined,
			selectEndDate: undefined,
			selectMinDate: undefined,
			selectMaxDate: undefined,
			startMonthAry: [],
			endMonthAry: [],
			clickCount: 0,
			is_add: false
		};
	},
	computed: {},
	watch: {},
	created() {
		if (this.startDate && this.endDate) {
			const startDateValue = typeof this.startDate === 'string' ? this.startDate : this.startDate.getTime();
			this.selectStartDate = new Date(startDateValue);
			const endDateValue = typeof this.endDate === 'string' ? this.endDate : this.endDate.getTime();
			this.selectEndDate = new Date(endDateValue);
			this.updateValue();
		}
		if (this.minDate) {
			const minDateValue = typeof this.minDate === 'string' ? this.minDate : this.minDate.getTime();
			this.selectMinDate = new Date(minDateValue);
		}
		if (this.maxDate) {
			const maxDateValue = typeof this.maxDate === 'string' ? this.maxDate : this.maxDate.getTime();
			this.selectMaxDate = new Date(maxDateValue);
		}
		this.updateCalendar(); // after setting
	},
	mounted() {},
	methods: {
		close() {
			this.active = false;
			this.$emit('close');
		},
		reset() {
			this.selectStartDate = undefined;
			this.selectEndDate = undefined;
			this.value = '';
			this.$emit('reset');
		},
		confirm() {
			if (this.selectStartDate && !this.selectEndDate) {
				this.selectEndDate = new Date(this.selectStartDate.getTime());
				this.selectEndDate.setDate(this.selectStartDate.getDate() + 1);
				this.updateValue();
			}
			if (this.selectStartDate && this.selectEndDate) {
				const dateResult = {
					start: this.displayDateText(this.selectStartDate),
					end: this.displayDateText(this.selectEndDate)
				};
				this.$emit('comform', dateResult);
				this.active = false;
			}
		},
		displayDateText(datetime) {
			if (datetime) {
				datetime = typeof datetime === 'string' ? new Date(datetime) : datetime;
				const yyyy = datetime.getFullYear();
				const mm = datetime.getMonth() + 1 > 9 ? datetime.getMonth() + 1 : `0${datetime.getMonth() + 1}`;
				const dd = datetime.getDate() > 9 ? datetime.getDate() : `0${datetime.getDate()}`;
				const displayStr = (this.format || 'YYYY/MM/DD')
					.replace('YYYY', yyyy)
					.replace('MM', mm)
					.replace('DD', dd);
				return displayStr;
			} else {
				return undefined;
			}
		},
		generateCalendar(calculateYear = new Date().getFullYear(), calculateMonth = new Date().getMonth(), config = {}) {
			const showPreviousMonthDate = config.showPreviousMonthDate || false;
			const showNextMonthDate = config.showNextMonthDate || false;
			const baseDateTime = new Date(calculateYear, calculateMonth, 1, 0, 0, 0);
			let countTime = new Date(calculateYear, calculateMonth, 1, 0, 0, 0);
			let tempMonthAry = [];
			let tempWeekAry = [];
			let nextMonth = false;
			let completed = false;
			while (!nextMonth || (nextMonth && !completed)) {
				let day = countTime.getDay();
				let date = countTime.getDate();
				let month = countTime.getMonth();
				// check next month
				if (month !== calculateMonth) {
					nextMonth = true;
					if (day === 6 || (date === 1 && day === 0)) {
						completed = true;
					}
				}
				// Set date
				if (!nextMonth) {
					tempWeekAry[day] = new Date(countTime.getTime()); // date obj
				} else {
					tempWeekAry[day] = showNextMonthDate ? new Date(countTime.getTime()) : false;
				}
				// check previous
				if (countTime.getTime() === baseDateTime.getTime() && day !== 0) {
					// Fill previous
					let previousDay = day;
					let previousCountTime = new Date(countTime.getTime());
					previousCountTime.setDate(previousCountTime.getDate());
					if (showPreviousMonthDate) {
						while (previousDay !== 0) {
							// let previousDate = previousDateTime.getDate()
							let previousDateTime = new Date(previousCountTime.getTime());
							previousDay = previousDateTime.getDay();
							tempWeekAry[previousDay] = previousDateTime; // date obj
							previousCountTime.setDate(previousCountTime.getDate() - 1);
						}
					}
				}
				// check new week
				if ((countTime.getTime() === baseDateTime.getTime() && tempWeekAry.length === 7) || (countTime.getTime() > baseDateTime && day === 6)) {
					// Next week
					tempMonthAry.push(tempWeekAry);
					tempWeekAry = [];
				}
				// calculate next day
				countTime.setDate(countTime.getDate() + 1);
			}

			return tempMonthAry;
		},
		updateCalendar(offset = 0) {
			if (!this.startMonthDate) {
				this.startMonthDate = this.selectStartDate ? this.selectStartDate : new Date(new Date().getFullYear(), new Date().getMonth()); // now
			}

			this.startMonthDate.setMonth(this.startMonthDate.getMonth() + offset);
			this.endMonthDate = new Date(this.startMonthDate.getFullYear(), this.startMonthDate.getMonth() + 1);

			this.startMonthAry = [];
			this.endMonthAry = [];
			this.startMonthAry = this.generateCalendar(this.startMonthDate.getFullYear(), this.startMonthDate.getMonth());
			this.endMonthAry = this.generateCalendar(this.endMonthDate.getFullYear(), this.endMonthDate.getMonth());
		},
		updateValue() {
			this.value = `${this.displayDateText(this.selectStartDate)} ${this.seperator} ${this.displayDateText(this.selectEndDate)}`;
		},
		disabledPreviousArrow(datetime) {
			const now = new Date();
			const today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
			if (datetime && datetime.getFullYear() === today.getFullYear() && datetime.getMonth() === today.getMonth() && this.selectForward) {
				return 'disabled';
			}
		},
		dayStatus(datetime) {
			const classList = [];
			if (datetime) {
				const now = new Date();
				// const today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)
				// check status
				if (this.selectMinDate.getTime() > datetime.getTime()) {
					classList.push('disabled');
				} else if (this.selectMaxDate && this.selectMaxDate.getTime() < datetime.getTime()) {
					classList.push('disabled');
				} else if (this.disabledDates.indexOf(this.displayDateText(datetime)) > -1) {
					classList.push('disabled');
					classList.push('forbidden');
				} else if (this.selectStartDate && this.selectStartDate.getTime() > datetime.getTime() && !this.selectForward) {
					classList.push('disabled');
				} else if (this.selectStartDate && this.selectStartDate.getTime() === datetime.getTime()) {
					classList.push('start-date');
				} else if (this.selectEndDate && this.selectEndDate.getTime() === datetime.getTime()) {
					classList.push('end-date');
				} else if (this.selectStartDate && this.selectEndDate && datetime.getTime() > this.selectStartDate.getTime() && datetime.getTime() < this.selectEndDate.getTime()) {
					classList.push('in-date-range');
				}
				// check min night and max night
				if (
					this.selectStartDate &&
					this.selectStartDate.getTime() < datetime.getTime() &&
					((Number.isInteger(this.minNight) && this.minNight > 0) || (Number.isInteger(this.maxNight) && this.maxNight > 0))
				) {
					const night = (datetime.getTime() - this.selectStartDate.getTime()) / (1000 * 60 * 60 * 24);
					if (night < this.minNight) {
						classList.push('disabled');
					} else if (night > this.maxNight) {
						classList.push('disabled');
					}
				}
				// check today
				if (now.getFullYear() === datetime.getFullYear() && now.getMonth() === datetime.getMonth() && now.getDate() === datetime.getDate()) {
					classList.push('today');
				}
			}
			return classList;
		},
		dayOnClick(datetime) {
			if (datetime) {
				if (!this.selectStartDate) {
					this.selectStartDate = datetime;
				} else if (!this.selectEndDate) {
					if (this.selectStartDate && datetime.getTime() < this.selectStartDate.getTime()) {
						this.selectEndDate = this.selectStartDate;
						this.selectStartDate = datetime;
					} else {
						this.selectEndDate = datetime;
					}
				} else if (datetime.getTime() < this.selectStartDate.getTime()) {
					this.selectStartDate = datetime;
				} else if (datetime.getTime() > this.selectEndDate.getTime()) {
					this.selectEndDate = datetime;
				} else if (datetime.getTime() > this.selectStartDate.getTime() && datetime.getTime() < this.selectEndDate.getTime()) {
					if (this.clickCount % 2 === 0) {
						this.selectStartDate = datetime;
					} else {
						this.selectEndDate = datetime;
					}
					this.clickCount++;
				}
				const dateResult = {
					start: this.displayDateText(this.selectStartDate),
					end: this.displayDateText(this.selectEndDate)
				};
				this.$emit('update', dateResult);

				if (this.selectStartDate && this.selectEndDate) {
					this.updateValue();
				}
			}
		}
	}
};
</script>
<style scoped>
.confirm {
	width: 590px;
	height: 98px;
	background-image: linear-gradient(0deg, #21a1a0 0%, #3bc3c2 100%);
	margin: 0 auto;
	margin-bottom: 35px;
	font-family: MicrosoftYaHei;
	font-size: 36px;
	font-weight: normal;
	font-stretch: normal;
	line-height: 48px;
	letter-spacing: 0px;
	color: #ffffff;
	border-radius: 10px;
	text-align: center;
	line-height: 98px;
}
.vhd-picker {
	position: fixed;
	top: 0;
	left: 0;
	bottom: 0;
	right: 0;
	background: rgba(0, 0, 0, 0.5);
}
.vhd-calendar{
	width: 671px;
	background-color: #ffffff;
	position: fixed;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	border-radius: 10px;
}
/* //月 */
.calendar-month-title {
	padding-top: 39px;
	text-align: center;
	padding-bottom: 55px;
	font-family: MicrosoftYaHei;
	font-size: 33px;
	font-weight: normal;
	font-stretch: normal;
	letter-spacing: 0px;
	color: #444444;
}
/* //周 */
.calendar-week {
	display: flex;
}
.calendar-week .calendar-week-item {
	flex: 1;
	text-align: center;
	font-family: MicrosoftYaHei;
	font-size: 32px;
	font-weight: normal;
	font-stretch: normal;
	letter-spacing: 2px;
	color: #3bc3c2;
	padding-bottom: 49px;
}
/* //天 */
.calendar-date {
	height: 600px;
	overflow: hidden;
}
.vhd-calendar-right {
	display: none;
}
.week .day {
	width: 14.28%;
	float: left;
	text-align: center;
	margin-bottom: 62px;
	height: 56px;
	line-height: 56px;
	font-family: MicrosoftYaHei;
	font-size: 32px;
	font-weight: normal;
	font-stretch: normal;
	letter-spacing: 0px;
	color: #444444;
}
.week .day.start-date span {
	width: 56px;
	height: 56px;
	background: #3bc3c2;
	color: #fff;
	display: block;
	margin: 0 auto;
	border-radius: 50%;
	position: relative;
}
.days li {
	position: relative;
}
.week .day.start-date:after {
	background: rgba(59, 195, 194, 0.5);
	display: block;
	border-bottom-left-radius: 56px;
	border-top-left-radius: 56px;
	content: '';
	display: inline-block;
	width: 56px;
	height: 56px;
	right: 0;
	top: 0;
	position: absolute;
	z-index: -1;
}
.week .day {
	position: relative;
}
.week .day.in-date-range {
	background: rgba(59, 195, 194, 0.5);
}
.week .day.end-date:before {
	background: rgba(59, 195, 194, 0.5);
	display: block;
	border-bottom-right-radius: 56px;
	border-top-right-radius: 56px;
	content: '';
	display: inline-block;
	width: 56px;
	height: 56px;
	left: 0;
	position: absolute;
	z-index: -1;
}
.week .day.end-date span {
	width: 56px;
	height: 56px;
	background: #3bc3c2;
	color: #fff;
	display: block;
	margin: 0 auto;
	border-radius: 50%;
	position: relative;
}
.week .day.start-date span:after {
	position: absolute;
	top: 56px;
	width: 56px;
	height: 56px;
	content: '入住';
	display: block;
	font-family: MicrosoftYaHei;
	font-size: 26px;
	font-weight: normal;
	font-stretch: normal;
	letter-spacing: 0px;
	color: #444444;
}
.week .day.end-date span:after {
	position: absolute;
	width: 56px;
	height: 56px;
	content: '离店';
	display: block;
	font-family: MicrosoftYaHei;
	font-size: 26px;
	font-weight: normal;
	font-stretch: normal;
	letter-spacing: 0px;
	color: #444444;
}
.active span {
	width: 56px;
	height: 56px;
	background: #3bc3c2;
	color: #fff;
	display: block;
	margin: 0 auto;
	border-radius: 50%;
}
.week .day.disabled {
	font-family: MicrosoftYaHei;
	font-size: 32px;
	font-weight: normal;
	font-stretch: normal;
	color: #8a8a8a;
}
.mouth {
	display: flex;
	margin-bottom: 40px;
}
.mouth .previous-arrow {
	flex: 1;
	height: 48px;
	font-family: MicrosoftYaHei;
	font-size: 24px;
	display: block;
	font-weight: normal;
	font-stretch: normal;
	letter-spacing: 0px;
	color: #8a8a8a;
	display: flex;
}
.mouth .previous-arrow:nth-child(1) {
	text-align: left;
}
.mouth .previous-arrow:nth-child(2) {
	text-align: right;
}
.mouth .previous-arrow:nth-child(1) span{
	flex: 1;
	line-height: 48px;
}
.mouth .previous-arrow:nth-child(2) span{
	flex: 1;
	line-height: 48px;
}
</style>
